home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / MPW_TOOL / TOOLS / TOOLS_WI / ICON_8 / ICONT_FO / TLEX.C < prev    next >
Text File  |  1990-03-02  |  19KB  |  743 lines

  1. /*
  2.  * tlex.c -- the lexical analyzer.
  3.  */
  4.  
  5. #include "::h:config.h"
  6. #include "tproto.h"
  7. #include "trans.h"
  8. #include "token.h"
  9. #include "tlex.h"
  10. #include "tree.h"
  11. #include <ctype.h>
  12.  
  13. #if MACINTOSH
  14. #if MPW
  15. #include <CursorCtl.h>
  16. #define CURSORINTERVAL 100
  17. #endif                    /* MPW */
  18. #endif                    /* MACINTOSH */
  19.  
  20. /*
  21.  * Prototypes.
  22.  */
  23.  
  24. hidden    int        ctlesc        Params((noargs));
  25. hidden    struct toktab   *findres    Params((noargs));
  26. hidden    struct toktab   *getident    Params((int ac,int *cc));
  27. hidden    struct toktab   *getnum        Params((int ac,int *cc));
  28. hidden    struct toktab   *getopr        Params((int ac,int *cc));
  29. hidden    struct toktab   *getstring    Params((int ac,int *cc));
  30. hidden    int        hexesc        Params((noargs));
  31. hidden    int        nextchar    Params((noargs));
  32. hidden    int        octesc        Params((int ac));
  33. hidden    int        setfilenm    Params((int c));
  34. hidden    int        setlineno    Params((noargs));
  35.  
  36. #define isletter(s)    (isupper(c) | islower(c))
  37.  
  38. #if !EBCDIC
  39. #define tonum(c)    (isdigit(c) ? (c - '0') : ((c & 037) + 9))
  40.  
  41. /*
  42.  * esctab - translates single-character escapes in string literals.
  43.  */
  44.  
  45. static char esctab[] = {
  46.    000,   001,     002,    003,   004,   005,   006,   007,   /* NUL-BEL */
  47.    010,   011,     012,    013,   014,   015,   016,   017,   /* BS -SI */
  48.    020,   021,     022,    023,   024,   025,   026,   027,   /* DLE-ETB */
  49.    030,   031,     032,    033,   034,   035,   036,   037,   /* CAN-US */
  50.    ' ',   '!',   '"',   '#',   '$',   '%',   '&',   '\'',  /* !"#$%&' */
  51.    '(',   ')',   '*',   '+',   ',',   '-',   '.',   '/',   /* ()*+,-./ */
  52.    000,   001,     002,    003,   004,   005,   006,   007,   /* 01234567 */
  53.    010,   011,     ':',   ';',   '<',   '=',   '>',   '?',   /* 89:;<=>? */
  54.    '@',   'A',   '\b',  'C',   0177,  033,   014,   'G',   /* @ABCDEFG */
  55.    'H',   'I',   'J',   'K',   '\n',  'M',  '\n',   'O',   /* HIJKLMNO */
  56.    'P',   'Q',   '\r',  'S',   '\t',  'U',   013,   'W',   /* PQRSTUVW */
  57.    'X',   'Y',   'Z',   '[',   '\\',  ']',   '^',   '_',   /* XYZ[\]^_ */
  58.    '`',   'a',   '\b',  'c',   0177,  033,   014,   'g',   /* `abcdefg */
  59.    'h',   'i',   'j',   'k',   '\n',  'm',   '\n',  'o',   /* hijklmno */
  60.    'p',   'q',   '\r',  's',   '\t',  'u',   013,   'w',   /* pqrstuvw */
  61.    'x',   'y',   'z',   '{',   '|',   '}',   '~',   0177,  /* xyz{|}~ */
  62.    0200,  0201,  0202,    0203,  0204,  0205,  0206,  0207,
  63.    0210,  0211,  0212,    0213,  0214,  0215,  0216,  0217,
  64.    0220,  0221,  0222,    0223,  0224,  0225,  0226,  0227,
  65.    0230,  0231,  0232,    0233,  0234,  0235,  0236,  0237,
  66.    0240,  0241,  0242,    0243,  0244,  0245,  0246,  0247,
  67.    0250,  0251,  0252,    0253,  0254,  0255,  0256,  0257,
  68.    0260,  0261,  0262,    0263,  0264,  0265,  0266,  0267,
  69.    0270,  0271,  0272,    0273,  0274,  0275,  0276,  0277,
  70.    0300,  0301,  0302,    0303,  0304,  0305,  0306,  0307,
  71.    0310,  0311,  0312,    0313,  0314,  0315,  0316,  0317,
  72.    0320,  0321,  0322,    0323,  0324,  0325,  0326,  0327,
  73.    0330,  0331,  0332,    0333,  0334,  0335,  0336,  0337,
  74.    0340,  0341,  0342,    0343,  0344,  0345,  0346,  0347,
  75.    0350,  0351,  0352,    0353,  0354,  0355,  0356,  0357,
  76.    0360,  0361,  0362,    0363,  0364,  0365,  0366,  0367,
  77.    0370,  0371,  0372,    0373,  0374,  0375,  0376,  0377,
  78.   };
  79. #else                    /* !EBCDIC */
  80. /*
  81.  *  This is the EBCDIC table for handling escapes.
  82.  */
  83. static char esctab[] = {
  84.    0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,
  85.    0x08,  0x09,  0x0a,  0x0b,  0x0c,  0x0d,  0x0e,  0x0f,
  86.    0x10,  0x11,  0x12,  0x13,  0x14,  0x15,  0x16,  0x17,
  87.    0x18,  0x19,  0x1a,  0x1b,  0x1c,  0x1d,  0x1e,  0x1f,
  88.    0x20,  0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x27,
  89.    0x28,  0x29,  0x2a,  0x2b,  0x2c,  0x2d,  0x2e,  0x2f,
  90.    0x30,  0x31,  0x32,  0x33,  0x34,  0x35,  0x36,  0x37,
  91.    0x38,  0x39,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,
  92.    ' ',   0x41,  0x42,  0x43,  0x44,  0x45,  0x46,  0x47,
  93.    0x48,  0x49,  0x4a,  0x4b,  0x4c,  0x4d,  0x4e,  0x4f,
  94.    0x50,  0x51,  0x52,  0x53,  0x54,  0x55,  0x56,  0x57,
  95.    0x58,  0x59,  0x5a,  0x5b,  0x5c,  0x5d,  0x5e,  0x5f,
  96.    0x60,  0x61,  0x62,  0x63,  0x64,  0x65,  0x66,  0x67,
  97.    0x68,  0x69,  0x6a,  0x6b,  0x6c,  0x6d,  0x6e,  0x6f,
  98.    0x70,  0x71,  0x72,  0x73,  0x74,  0x75,  0x76,  0x77,
  99.    0x78,  0x79,  0x7a,  0x7b,  0x7c,  0x7d,  0x7e,  0x7f,
  100.    0x80,  'a',   0x16,  'c',   0x07,  0x27,  0x0c,  'g',
  101.    'h',   'i',   0x8a,  0x8b,  0x8c,  0x8d,  0x8e,  0x8f,
  102.    0x90,  'j',   'k',   0x25,  'm',   0x15,  'o',   'p',
  103.    'q',   0x0d,  0x9a,  0x9b,  0x9c,  0x9d,  0x9e,  0x9f,
  104.    0xa0,  0xa1,  's',   0x05,  'u',   0x0b,  'w',   'x',
  105.    'y',   'z',   0xaa,  0xab,  0xac,  0xad,  0xae,  0xaf,
  106.    0xb0,  0xb1,  0xb2,  0xb3,  0xb4,  0xb5,  0xb6,  0xb7,
  107.    0xb8,  0xb9,  0xba,  0xbb,  0xbc,  0xbd,  0xbe,  0xbf,
  108.    0xc0,  'A',   0x16,  'C',   0x07,  0x27,  0x0c,  'G',
  109.    'H',   'I',   0xca,  0xcb,  0xcc,  0xcd,  0xce,  0xcf,
  110.    0xd0,  'J',   'K',   0x25,  'M',   0x15,  'O',   'P',
  111.    'Q',   0x0d,  0xda,  0xdb,  0xdc,  0xdd,  0xde,  0xdf,
  112.    0xe0,  0xe1,  'S',   0x05,  'U',   0x0b,  'W',   'X',
  113.    'Y',   'Z',   0xea,  0xeb,  0xec,  0xed,  0xee,  0xef,
  114.    0,   1,   2,   3,     4,     5,     6,     7,
  115.    8,   9,   0xfa,   0xfb,  0xfc,  0xfd,  0xfe,  0xff,
  116.    };
  117. #endif               /* !EBCDIC */
  118.  
  119. struct node tok_loc =
  120.    {0, NULL, 0, 0};    /* "model" node containing location of current token */
  121.  
  122. /*
  123.  * yylex - find the next token in the input stream, and return its token
  124.  *  type and value to the parser.
  125.  *
  126.  * Variables of interest:
  127.  *
  128.  *  cc - character following last token.
  129.  *  comflag - set if in a comment.
  130.  *  nlflag - set if a newline was between the last token and the current token
  131.  *  lastend - set if the last token was an Ender.
  132.  *  lastval - when a semicolon is inserted and returned, lastval gets the
  133.  *   token value that would have been returned if the semicolon hadn't
  134.  *   been inserted.
  135.  */
  136.  
  137. static struct toktab *lasttok = NULL;
  138. static int lastend = 0;
  139. static int eofflag = 0;
  140. static int cc = '\n';
  141.  
  142. int yylex()
  143.    {
  144.    register struct toktab *t;
  145.    register int c;
  146.    int nlflag;
  147.    int comflag;
  148.    static nodeptr lastval;
  149.    static struct node semi_loc;
  150.  
  151.    if (lasttok != NULL) {
  152.       /*
  153.        * A semicolon was inserted and returned on the last call to yylex,
  154.        *  instead of going to the input, return lasttok and set the
  155.        *  appropriate variables.
  156.        */
  157.  
  158.       yylval = lastval;
  159.       tok_loc = *lastval;
  160.       t = lasttok;
  161.       goto ret;
  162.       }
  163.    nlflag = 0;
  164.    comflag = 0;
  165. loop:
  166.    c = cc;
  167.    /*
  168.     * Remember where a semicolon will go if we insert one.
  169.     */
  170.    semi_loc.n_file = tok_loc.n_file;
  171.    semi_loc.n_line = in_line;
  172.    semi_loc.n_col = incol;
  173.    /*
  174.     * Skip whitespace and comments and process #line directives.
  175.     */
  176.    while (c == Comment || isspace(c)) {
  177.       if (c == '\n') {
  178.          nlflag++;
  179.          c = NextChar;
  180.      if (c == Comment) {
  181.             /*
  182.          * Check for #line directive at start of line.
  183.              */
  184.             if (('l' == (c = NextChar)) &&
  185.                 ('i' == (c = NextChar)) &&
  186.                 ('n' == (c = NextChar)) &&
  187.                 ('e' == (c = NextChar))) {
  188.                c = setlineno();
  189.            while ((c == ' ') || (c == '\t'))
  190.           c = NextChar;
  191.                if (c != EOF && c != '\n')
  192.                   c = setfilenm(c);
  193.            }
  194.         while (c != EOF && c != '\n')
  195.                c = NextChar;
  196.         }
  197.          }
  198.       else {
  199.      if (c == Comment) {
  200.         while (c != EOF && c != '\n')
  201.                c = NextChar;
  202.         }
  203.          else {
  204.             c = NextChar;
  205.             }
  206.          }
  207.       }
  208.    /*
  209.     * A token is the next thing in the input.  Set token location to
  210.     *  the current line and column.
  211.     */
  212.    tok_loc.n_line = in_line;
  213.    tok_loc.n_col = incol;
  214.  
  215.    if (c == EOF) {
  216.       /*
  217.        * End of file has been reached.    Set eofflag, return T_Eof, and
  218.        *  set cc to EOF so that any subsequent scans also return T_Eof.
  219.        */
  220.       if (eofflag++) {
  221.      eofflag = 0;
  222.      cc = '\n';
  223.      yylval = NULL;
  224.      return 0;
  225.      }
  226.       cc = EOF;
  227.       t = T_Eof;
  228.       yylval = NULL;
  229.       goto ret;
  230.       }
  231.  
  232.    /*
  233.     * Look at current input character to determine what class of token
  234.     *  is next and take the appropriate action.  Note that the various
  235.     *  token gathering routines write a value into cc.
  236.     */
  237.    if (isalpha(c) || (c == '_')) {   /* gather ident or reserved word */
  238.       if ((t = getident(c, &cc)) == NULL)
  239.      goto loop;
  240.       }
  241.    else if (isdigit(c)) {        /* gather numeric literal */
  242.       if ((t = getnum(c, &cc)) == NULL)
  243.      goto loop;
  244.       }
  245.    else if (c == '"' || c == '\'') {    /* gather string or cset literal */
  246.       if ((t = getstring(c, &cc)) == NULL)
  247.      goto loop;
  248.       }
  249.    else {            /* gather longest legal operator */
  250.       if ((t = getopr(c, &cc)) == NULL)
  251.      goto loop;
  252.       yylval = OpNode(t->t_type);
  253.       }
  254.    if (nlflag && lastend && (t->t_flags & Beginner)) {
  255.       /*
  256.        * A newline was encountered between the current token and the last,
  257.        *  the last token was an Ender, and the current token is a Beginner.
  258.        *  Return a semicolon and save the current token in lastval.
  259.        */
  260.       lastval = yylval;
  261.       lasttok = t;
  262.       tok_loc = semi_loc;
  263.       yylval = OpNode(SEMICOL);
  264.       return SEMICOL;
  265.       }
  266. ret:
  267.    /*
  268.     * Clear lasttok, set lastend if the token being returned is an
  269.     *  Ender, and return the token.
  270.     */
  271.    lasttok = 0;
  272.    lastend = t->t_flags & Ender;
  273.    return (t->t_type);
  274.    }
  275.  
  276. #ifdef MultipleRuns
  277. /*
  278.  * yylexinit - initialize variables for multiple runs
  279.  */
  280. novalue yylexinit()
  281.    {
  282.    lasttok = NULL;
  283.    lastend = 0;
  284.    eofflag = 0;
  285.    cc = '\n';
  286.    }
  287.  
  288. #endif                    /* MultipleRuns */
  289. /*
  290.  * getident - gather an identifier beginning with ac.  The character
  291.  *  following identifier goes in cc.
  292.  */
  293.  
  294. static struct toktab *getident(ac, cc)
  295. int ac;
  296. int *cc;
  297.    {
  298.    register int c;
  299.    register char *p;
  300.    register struct toktab *t;
  301.  
  302.    c = ac;
  303.    p = strf;
  304.    /*
  305.     * Copy characters into string space until a non-alphanumeric character
  306.     *  is found.
  307.     */
  308.    do {
  309.       if (p >= stre)
  310.      tsyserr("out of string space");
  311.       *p++ = c;
  312.       c = NextChar;
  313.       } while (isalnum(c) || (c == '_'));
  314.    if (p >= stre)
  315.       tsyserr("out of string space");
  316.    *p++ = 0;
  317.    *cc = c;
  318.    /*
  319.     * If the identifier is a reserved word, make a ResNode for it and return
  320.     *  the token value.  Otherwise, install it with putid, make an
  321.     *  IdNode for it, and return.
  322.     */
  323.    if ((t = findres()) != NULL) {
  324.       yylval = ResNode(t->t_type);
  325.       return t;
  326.       }
  327.    else {
  328.       yylval = IdNode(putid((int)(p-strf)));
  329.       return (struct toktab *)T_Ident;
  330.       }
  331.    }
  332.  
  333. /*
  334.  * findres - if the string just copied into the string space by getident
  335.  *  is a reserved word, return a pointer to its entry in the token table.
  336.  *  Return NULL if the string isn't a reserved word.
  337.  */
  338.  
  339. static struct toktab *findres()
  340.    {
  341.    register struct toktab *t;
  342.    register char c, *p;
  343.  
  344.    p = strf;
  345.    c = *p;
  346.    if (!islower(c))
  347.       return NULL;
  348.    /*
  349.     * Point t at first reserved word that starts with c (if any).
  350.     */
  351.    if ((t = restab[c - 'a']) == NULL)
  352.       return NULL;
  353.    /*
  354.     * Search through reserved words, stopping when a match is found
  355.     *  or when the current reserved word doesn't start with c.
  356.     */
  357.    while (t->t_word[0] == c) {
  358.       if (strcmp(t->t_word, p) == 0)
  359.      return t;
  360.       t++;
  361.       }
  362.    return NULL;
  363.    }
  364.  
  365. /*
  366.  * getnum - gather a numeric literal starting with ac and put the
  367.  *  character following the literal into *cc.
  368.  */
  369.  
  370. static struct toktab *getnum(ac, cc)
  371. int ac;
  372. int *cc;
  373.    {
  374.    register int c, r, state;
  375.    char *p;
  376.    int realflag;
  377.  
  378.    c = ac;
  379.    r = tonum(c);
  380.    p = strf;
  381.    state = 0;
  382.    realflag = 0;
  383.    for (;;) {
  384.       if (p >= stre)
  385.      tsyserr("out of string space");
  386.       *p++ = c;
  387.       c = NextChar;
  388.       switch (state) {
  389.      case 0:        /* integer part */
  390.         if (isdigit(c))        { r = r * 10 + tonum(c); continue; }
  391.         if (c == '.')           { state = 1; realflag++; continue; }
  392.         if (c == 'e' || c == 'E')  { state = 2; realflag++; continue; }
  393.         if (c == 'r' || c == 'R')  {
  394.            state = 5;
  395.            if (r < 2 || r > 36)
  396.           tfatal("invalid radix for integer literal", (char *)NULL);
  397.            continue;
  398.            }
  399.         break;
  400.      case 1:        /* fractional part */
  401.         if (isdigit(c))   continue;
  402.         if (c == 'e' || c == 'E')   { state = 2; continue; }
  403.         break;
  404.      case 2:        /* optional exponent sign */
  405.         if (c == '+' || c == '-') { state = 3; continue; }
  406.      case 3:        /* first digit after e, e+, or e- */
  407.         if (isdigit(c)) { state = 4; continue; }
  408.         tfatal("invalid real literal", (char *)NULL);
  409.         break;
  410.      case 4:        /* remaining digits after e */
  411.         if (isdigit(c))   continue;
  412.         break;
  413.      case 5:        /* first digit after r */
  414.         if ((isdigit(c) || isletter(c)) && tonum(c) < r)
  415.            { state = 6; continue; }
  416.         tfatal("invalid integer literal", (char *)NULL);
  417.         break;
  418.      case 6:        /* remaining digits after r */
  419.         if (isdigit(c) || isletter(c)) {
  420.            if (tonum(c) >= r) {    /* illegal digit for radix r */
  421.           tfatal("invalid digit in integer literal", (char *)NULL);
  422.           r = tonum('z');       /* prevent more messages */
  423.           }
  424.            continue;
  425.            }
  426.         break;
  427.      }
  428.       break;
  429.       }
  430.    if (p >= stre)
  431.       tsyserr("out of string space");
  432.    *p++ = 0;
  433.    *cc = c;
  434.    if (realflag) {
  435.       yylval = RealNode(putid((int)(p-strf)));
  436.       return T_Real;
  437.       }
  438.    yylval = IntNode(putid((int)(p-strf)));
  439.    return T_Int;
  440.    }
  441.  
  442. /*
  443.  * getstring - gather a string literal starting with ac and place the
  444.  *  character following the literal in *cc.
  445.  */
  446.  
  447. static struct toktab *getstring(ac, cc)
  448. int ac;
  449. int *cc;
  450.    {
  451.    register int c, sc;
  452.    register char *p;
  453.    char *lc;
  454.    int len;
  455.  
  456.    sc = c = ac;
  457.    p = strf;
  458.    lc = 0;
  459.    while ((c = NextChar) != sc && c != '\n' && c != EOF) {
  460.    contin:
  461.       if (c == '_')
  462.      lc = p;
  463.       else if (!isspace(c))
  464.      lc = 0;
  465.       if (c == Escape) {
  466.      c = NextChar;
  467.  
  468. #ifdef VarTran
  469.      *p++ = Escape;
  470. #else                    /* VarTran */
  471.      if (isoctal(c))
  472.         c = octesc(c);
  473.      else if (c == 'x')
  474.         c = hexesc();
  475.      else if (c == '^')
  476.         c = ctlesc();
  477.      else
  478.         c = esctab[c];
  479. #endif                    /* VarTran */
  480.  
  481.      if (c == EOF)
  482.         goto noquote;
  483.      }
  484.       if (p >= stre)
  485.      tsyserr("out of string space");
  486.       *p++ = c;
  487.       }
  488.    if (p >= stre)
  489.       tsyserr("out of string space");
  490.    *p++ = 0;
  491.    if (c == sc)
  492.       *cc = ' ';
  493.    else {
  494.       if (c == '\n' && lc) {
  495.      p = lc;
  496.      while ((c = NextChar) != EOF && isspace(c)) ;
  497.      if (c != EOF)
  498.         goto contin;
  499.      }
  500. noquote:
  501.       tfatal("unclosed quote", (char *)NULL);
  502.       *cc = c;
  503.       }
  504.    if (ac == '"') {     /* a string literal */
  505.       len = p - strf;
  506.       yylval = StrNode(putid((int)len), len);
  507.       return T_String;
  508.       }
  509.    else {        /* a cset literal */
  510.       len = p - strf;
  511.       yylval = CsetNode(putid((int)len), len);
  512.       return T_Cset;
  513.       }
  514.    }
  515.  
  516. #ifndef VarTran
  517.  
  518. /*
  519.  * ctlesc - translate a control escape -- backslash followed by
  520.  *  caret and one character.
  521.  */
  522.  
  523. static int ctlesc()
  524.    {
  525.    register int c;
  526.  
  527.    c = NextChar;
  528.    if (c == EOF)
  529.       return EOF;
  530.    return (c & 037);
  531.    }
  532.  
  533. /*
  534.  * octesc - translate an octal escape -- backslash followed by
  535.  *  one, two, or three octal digits.
  536.  */
  537.  
  538. static int octesc(ac)
  539. int ac;
  540.    {
  541.    register int c, nc, i;
  542.  
  543.    c = 0;
  544.    nc = ac;
  545.    i = 1;
  546.    do {
  547.       c = (c << 3) | (nc - '0');
  548.       nc = NextChar;
  549.       if (nc == EOF)
  550.      return EOF;
  551.       } while (isoctal(nc) && i++ < 3);
  552.    PushChar(nc);
  553.    return (c & 0377);
  554.    }
  555.  
  556. /*
  557.  * hexesc - translate a hexadecimal escape -- backslash-x
  558.  *  followed by one or two hexadecimal digits.
  559.  */
  560.  
  561. static int hexesc()
  562.    {
  563.    register int c, nc, i;
  564.  
  565.    c = 0;
  566.    i = 0;
  567.    while (i++ < 2) {
  568.       nc = NextChar;
  569.       if (nc == EOF)
  570.      return EOF;
  571.       if (nc >= 'a' && nc <= 'f')
  572.      nc -= 'a' - 10;
  573.       else if (nc >= 'A' && nc <= 'F')
  574.      nc -= 'A' - 10;
  575.       else if (isdigit(nc))
  576.      nc -= '0';
  577.       else {
  578.      PushChar(nc);
  579.      break;
  580.      }
  581.       c = (c << 4) | nc;
  582.       }
  583.    return c;
  584.    }
  585.  
  586. #endif                    /* VarTran */
  587.  
  588. /*
  589.  * getopr - find the longest legal operator and return a pointer
  590.  *  to its entry in the token table.
  591.  */
  592.  
  593. static struct toktab *getopr(ac, cc)
  594. int ac;
  595. int *cc;
  596.    {
  597.    register struct optab *state;
  598.    register char c, i;
  599.  
  600.    state = state0;
  601.    c = ac;
  602.    for (;;) {
  603.       while ((i = state->o_input) && c != i)
  604.      state++;
  605.       switch (state->o_action) {
  606.      case A_Goto:
  607.         state = (struct optab *) state->o_val;
  608.         c = NextChar;
  609.         continue;
  610.      case A_Error:
  611.         tfatal("invalid character", (char *)NULL);
  612.         *cc = ' ';
  613.         return NULL;
  614.      case A_Return:
  615.         *cc = c;
  616.         return (struct toktab *)(state->o_val);
  617.      case A_Immret:
  618.         *cc = ' ';
  619.         return (struct toktab *)(state->o_val);
  620.      }
  621.       }
  622.    }
  623.  
  624. /*
  625.  * setlineno - set line number from #line comment, return following char.
  626.  */
  627.  
  628. static int setlineno()
  629.    {
  630.    register int c;
  631.  
  632.    while ((c = NextChar) == ' ' || c == '\t')
  633.       ;
  634.    if (c < '0' || c > '9') {
  635.       tfatal("no line number in #line directive", "");
  636.       while (c != EOF && c != '\n')
  637.      c = NextChar;
  638.       return c;
  639.       }
  640.    in_line = 0;
  641.    while (c >= '0' && c <= '9') {
  642.       in_line = in_line * 10 + (c - '0');
  643.       c = NextChar;
  644.       }
  645.    return c;
  646.    }
  647.  
  648. /*
  649.  * setfilenm -    set file name from #line comment, return following char.
  650.  *
  651.  * Assigning to comfile here does not provide the fine-grained
  652.  * control over filenames required by a real macro processor.
  653.  * setloc() in tcode.c ought to be restored to its earlier form and
  654.  * the initialization of filenames fixed.
  655.  */
  656.  
  657. static int setfilenm(c)
  658. register int c;
  659.    {
  660.    extern char *comfile;
  661.    register char *p;
  662.  
  663.    while (c == ' ' || c == '\t')
  664.       c = NextChar;
  665.    if (c != '"') {
  666.       tfatal("'\"' missing from file name in #line directive", "");
  667.       while (c != EOF && c != '\n')
  668.      c = NextChar;
  669.       return c;
  670.       }
  671.    p = strf;
  672.    while ((c = NextChar) != '"' && c != EOF && c != '\n') {
  673.       if (p >= stre)
  674.      tsyserr("out of string space");
  675.       *p++ = c;
  676.       }
  677.    *p++ = '\0';
  678.    if (c == '"') {
  679.       tok_loc.n_file = putid((int)(p-strf));
  680.       return NextChar;
  681.       }
  682.    else {
  683.       tfatal("'\"' missing from file name in #line directive", "");
  684.       return c;
  685.       }
  686.    }
  687.  
  688. /*
  689.  * nextchar - return the next character in the input.
  690.  */
  691.  
  692. static int nextchar()
  693.    {
  694.    register int c;
  695.  
  696. #if MACINTOSH
  697. #if MPW
  698.    {
  699.    static short cursorcount = CURSORINTERVAL;
  700.    if (--cursorcount == 0) {
  701.       RotateCursor(0);
  702.       cursorcount = CURSORINTERVAL;
  703.       }
  704.    }
  705. #endif                    /* MPW */
  706. #endif                    /* MACINTOSH */
  707.  
  708.    if (c = peekc) {
  709.       peekc = 0;
  710.       return c;
  711.       }
  712.    c = getc(srcfile);
  713.    switch (c) {
  714.       case EOF:
  715.      if (incol) {
  716.         c = '\n';
  717.         in_line++;
  718.         incol = 0;
  719.         peekc = EOF;
  720.         break;
  721.         }
  722.      else {
  723.         in_line = 0;
  724.         incol = 0;
  725.         break;
  726.         }
  727.       case '\n':
  728.      in_line++;
  729.      incol = 0;
  730.      break;
  731.       case '\t':
  732.      incol = (incol | 7) + 1;
  733.      break;
  734.       case '\b':
  735.      if (incol)
  736.         incol--;
  737.      break;
  738.       default:
  739.      incol++;
  740.       }
  741.    return c;
  742.    }
  743.